`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2021/12/27 19:06:22
// Design Name: 
// Module Name: arp_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module arp_rx(
input                clk        , 
input                rst       ,                           
input                gmii_rx_dv , 
input        [7:0]   gmii_rxd   , 
output  reg          arp_rx_done,              //arp接受完成标志
output  reg          arp_rx_type,              //arp类型，0：请求，1：应答
output  reg  [47:0]  src_mac    ,              //源MAC
output  reg  [31:0]  src_ip                    //源IP
    );

parameter BOARD_IP = {8'd192,8'd168,8'd1,8'd102};
parameter BOARD_MAC = 48'h00_11_22_33_44_55;

typedef enum bit [7:0] {
    st_idle,                   //空闲状态
    st_preamble,               //前导码+SFD
    st_eth_head,               //以太网帧头
    st_arp_data,               //ARP数据包
    st_rx_done                 //接受完毕
} State;

State cur_state,next_state;
logic skip_en;
logic error_en;
logic [31:0] count;

logic [47:0] src_mac_t;
logic [31:0] src_ip_t;
logic [47:0] dest_mac_t;
logic [31:0] dest_ip_t;
logic [15:0] eth_type;
logic [15:0] arp_op;
//src_mac
always_ff@(posedge clk)
    src_mac<=src_mac_t;
//src_ip
always_ff@(posedge clk)
    src_ip<=src_ip_t;
//src_mac_t
always_ff@(posedge clk,posedge rst)
if(rst)
    src_mac_t<=0;
else if(cur_state==st_eth_head&&count>=6&&count<12)        //6-11,读取源MAC地址，高字节先来，所以进行左移
    src_mac_t<={src_mac_t[39:0],gmii_rxd};
//dest_mac
always_ff@(posedge clk,posedge rst)
if(rst)
    dest_mac_t<=0;
else if(cur_state==st_eth_head&&count>=0&&count<6)
    dest_mac_t<={dest_mac_t[39:0],gmii_rxd};
//src_ip_t
always_ff@(posedge clk,posedge rst)
if(rst)
    src_ip_t<=0;
else if(cur_state==st_arp_data&&count>=14&&count<18)
    src_ip_t<={src_ip_t[23:0],gmii_rxd};
//dest_ip
always_ff@(posedge clk,posedge rst)
if(rst)
    dest_ip_t<=0;
else if(cur_state==st_arp_data&&count>=24&&count<28)            
    dest_ip_t<={dest_ip_t[23:0],gmii_rxd};
else if(cur_state==st_idle)
    dest_ip_t<=0;
//arp_op
always_ff@(posedge clk,posedge rst)
if(rst)
    arp_op<=0;
else if(cur_state==st_arp_data&&count>=6&&count<8)                  //第6,7字节，从0开始计算
    arp_op<={arp_op[7:0],gmii_rxd};
//eth_type
always_ff@(posedge clk,posedge rst)
if(rst)
    eth_type<=0;
else if(cur_state==st_eth_head&&count>=12&&count<14)                 //第12，13个字节为以太网类型
    eth_type<={eth_type[7:0],gmii_rxd};
//cur_state
always_ff@(posedge clk,posedge rst)
if(rst)
    cur_state<=st_idle;
else
    cur_state<=next_state;
//next_state
always_comb
begin
    case(cur_state)
        st_idle:if(gmii_rx_dv)
                    next_state=st_preamble;
                else
                    next_state=st_idle;
        st_preamble:if(skip_en)
                        next_state=st_eth_head;
                    else if(error_en)
                        next_state=st_rx_done;
                    else
                        next_state=st_preamble;
        st_eth_head:if(skip_en)
                        next_state=st_arp_data;
                    else if(error_en)
                        next_state=st_rx_done;
                    else
                        next_state=st_eth_head;
        st_arp_data:if(skip_en||error_en)
                        next_state=st_rx_done;
                    else
                        next_state=st_arp_data;
        st_rx_done:if(skip_en)
                        next_state=st_idle;
                   else
                        next_state=st_rx_done;
        default:next_state=st_idle;
    endcase
end
//skip_en
always_comb
case(cur_state)
    st_idle:if(gmii_rx_dv)
                 skip_en=1;
            else
                 skip_en=0;
    st_preamble:if(count==6)                        //有一个数据在st_idle状态时接收了，因此st_preamble只有7个字节数据
                   skip_en=1;
                else
                   skip_en=0;
    st_eth_head:if(count==13)
                   skip_en=1;
                else
                   skip_en=0;
    st_arp_data:if(count==27)
                   skip_en=1;
                else
                   skip_en=0;
    st_rx_done:if(!gmii_rx_dv)
                   skip_en=1;
                else
                   skip_en=0;
    default:skip_en=0;
endcase
//error_en
always_ff@(posedge clk,posedge rst)
if(rst)
    error_en<=0;
else
begin
    case(cur_state)
        st_idle:if(gmii_rx_dv&&gmii_rxd!=8'h55)                      //第一个字节不是55
                    error_en<=1;
                else
                    error_en<=0;
        st_preamble:if(count<6&&gmii_rxd!=8'h55)                    //第1-6个字节不是55
                        error_en<=1; 
                    else if(count==6&&gmii_rxd!=8'hd5)                //SFD字节不是d5
                        error_en<=1;
                    else
                        error_en<=0;
        st_eth_head:if(count==6)            //目的MAC地址
                        if(dest_mac_t!=48'hff_ff_ff_ff_ff_ff&&dest_mac_t!=BOARD_MAC)        //既不是广播MAC，也不和本地MAC匹配，则丢弃
                            error_en<=1;
                        else
                            error_en<=0;
                    else
                       error_en<=0;
        st_arp_data:if(count==0&&eth_type!=16'h0806)               //判断以太网类型是否正确
                        error_en<=1;
                    else if(count==8&&(arp_op!=16'h0001&&arp_op!=0002))  //判断op操作码
                        error_en<=1;
                    else 
                        error_en<=0;
        st_rx_done:if(dest_ip_t!=BOARD_IP)                                //判断目标IP地址是否等于本地IP地址
                       error_en<=1;
                   else
                       error_en<=0;
        default:error_en<=0;
    endcase
end
//count
always_ff@(posedge clk,posedge rst)
if(rst)
    count<=0;
else
begin
    case(cur_state)
       st_idle:if(gmii_rx_dv)
                   count<=0;
       st_preamble:if(count==6)
                      count<=0;
                   else
                      count<=count+1;
       st_eth_head:if(count==13)
                      count<=0;
                   else
                      count<=count+1;
        st_arp_data:if(count==27)
                      count<=0;
                    else
                      count<=count+1;
        st_rx_done:count<=0;
        default:count<=0;
    endcase
end
//arp_rx_done arp_rx_type
always_ff@(posedge clk,posedge rst)
if(rst)
begin
    arp_rx_done<=0;
    arp_rx_type<=0;
end
else if(cur_state==st_rx_done)
begin
    if(dest_ip_t==BOARD_IP)
    begin
        arp_rx_done<=1;
        arp_rx_type<=arp_op-1;
    end
end
else if(cur_state==st_idle)
begin
    arp_rx_done<=0;
    arp_rx_type<=0;
end
endmodule
